package generate;

import java.io.File;
import java.io.FileNotFoundException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DecryptTest {

	public static void main(String[] args) {

		String bankKeyInHex = "9F7E3D9AB71D3F127E041ACF4355F962";
		String ivInHex = "683C4FCA500A1978A1A7983A0728A664";
		
		String aliceKeyInHex = "9AB4A3803097EA8CBE60DC8FDB319C67";
		String aliceIvInHex = "677DC667CFD9109D897B611B59A986B7";
		
		String bobKeyInHex = "623E88E34F5D3AF53A5026955A3F8C18";
		String bobIvInHex = "66C62F3C5A4CFCD04E07A27F9647F8E4";
		
		String carolKeyInHex = "584D97DB3B3ACEDB8E0CFF51312D35FB";
		String carolIvInHex = "B2E003196CD2A26063A68EDA4AD15344";

		// Initialize bank's key
		Key bankKey = new SecretKeySpec(hexStringToByteArray(bankKeyInHex), "AES");
		Key carolKey = new SecretKeySpec(hexStringToByteArray(carolKeyInHex), "AES");
		Key aliceKey = new SecretKeySpec(hexStringToByteArray(aliceKeyInHex), "AES");
		Key bobKey = new SecretKeySpec(hexStringToByteArray(bobKeyInHex), "AES");

		// Initialize bank's IV
		IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray(ivInHex));
		IvParameterSpec carolIv = new IvParameterSpec(hexStringToByteArray(carolIvInHex));
		IvParameterSpec bobIv = new IvParameterSpec(hexStringToByteArray(bobIvInHex));
		IvParameterSpec aliceIv = new IvParameterSpec(hexStringToByteArray(aliceIvInHex));

		// Initialize cipher
		Cipher ciph = null, ciphA = null, ciphB = null, ciphC = null;
		try {
			ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
			ciph.init(Cipher.DECRYPT_MODE, bankKey, iv);
			
			ciphA = Cipher.getInstance("AES/CBC/PKCS5Padding");
			ciphA.init(Cipher.DECRYPT_MODE, aliceKey, aliceIv);
			
			ciphB = Cipher.getInstance("AES/CBC/PKCS5Padding");
			ciphB.init(Cipher.DECRYPT_MODE, bobKey, bobIv);
			
			ciphC = Cipher.getInstance("AES/CBC/PKCS5Padding");
			ciphC.init(Cipher.DECRYPT_MODE, carolKey, carolIv);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			e.printStackTrace();
		}

		Scanner scan = null;
		try {
			scan = new Scanner(new File("userinfo.txt"));

			while(scan.hasNext()) {
				byte[] msgInBytes = hexStringToByteArray(scan.next());
				
				byte[] decryptedMessage = ciph.doFinal(msgInBytes);
				
				String msg = new String(decryptedMessage, Charset.forName("US-ASCII"));
				
				System.out.println(msg);
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		
		try {
			scan = new Scanner(new File("balance.txt"));

			int count = 0;
			while(scan.hasNext()) {
				byte[] msgInBytes = hexStringToByteArray(scan.next());
				
				byte[] decryptedMessage = null;
				
				if (count == 0) {
					decryptedMessage = ciphC.doFinal(msgInBytes);
				} else if (count == 1) {
					decryptedMessage = ciphA.doFinal(msgInBytes);
				} else {
					decryptedMessage = ciphB.doFinal(msgInBytes);
				}
				
				count++;
				
				String msg = new String(decryptedMessage, Charset.forName("US-ASCII"));
				
				System.out.println(msg);
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		
	}

	private static byte[] hexStringToByteArray(String s) {
		int len = s.length();
		byte[] data = new byte[len / 2];
		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
					+ Character.digit(s.charAt(i+1), 16));
		}
		return data;
	}
}
